package com.ttg.common.component.impl;

import com.ttg.common.component.LoginCrypto;
import com.ttg.common.config.ManageConfig;
import com.ttg.common.config.MctConfig;
import com.ttg.common.config.OrganConfig;
import com.ttg.common.dto.BasicDto;
import com.ttg.common.enums.CryptoKeyConfigTypeEnum;
import com.ttg.common.utils.BasicUtils;
import com.ttg.common.utils.sm.AsymmetricKey;
import com.ttg.common.utils.sm.GmUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import java.util.TreeMap;

/**
 * @ClassName GmLoginCryptoUtils
 * @Description 国密加密方式
 * 非对称使用SM2
 * 对称使用 SM4
 * 摘要算法为 SM3
 * @Author sss
 * @Date 2022/6/8
 * @Version 1.0
 **/
@Slf4j
@Component
public class GmLoginCryptoUtils extends LoginCrypto {

    @Autowired
    @Lazy
    private ManageConfig manageConfig;

    @Autowired
    @Lazy
    private OrganConfig organConfig;

    @Autowired
    @Lazy
    private MctConfig mctConfig;

    @Override
    public String messageDigest(String msg) {
        return GmUtils.sm3(msg);
    }

    /**
     * SM4 ECB解密 + hex2byte
     *
     * @param descyptStr 待解密字符串
     * @param key        密钥
     * @return
     * @throws Exception
     */
    @Override
    public String decrypt(String descyptStr, String key) throws Exception {
        return GmUtils.sm4ECBDecrypt(descyptStr, key);
    }


    /**
     * SM4 ECB加密 + byte2hex
     *
     * @param encryptStr 待加密字符串
     * @param key        密钥
     * @return
     * @throws Exception
     */
    @Override
    public String encrypt(String encryptStr, String key) throws Exception {
        return GmUtils.sm4ECBEncrypt(encryptStr, key);
    }

    /**
     * SM2 私钥解密 + hex2byte
     *
     * @param descyptStr    密文 hex串
     * @param privateKeyStr 私钥
     * @return
     * @throws Exception
     */
    @Override
    public String decryptByPrivateKey(String descyptStr, String privateKeyStr) throws Exception {
        return GmUtils.sm2DecryptByPrivateKey(descyptStr, privateKeyStr);
    }

    /**
     * SM2 公钥加密 + byte2hex
     *
     * @param encryptStr   明文
     * @param publicKeyStr 公钥 128 去除标记头后的非压缩公钥 hex串
     * @return 密文 hex
     * @throws Exception
     */
    @Override
    public String encryptByPublicKey(String encryptStr, String publicKeyStr) throws Exception {
        return GmUtils.sm2EncryptByPublicKey(encryptStr, publicKeyStr);
    }

    /**
     * 由于SM2 不支持私钥加密，公钥解密，这里私钥加密实际还是调用公钥加密
     *
     * @param encryptStr    密文（hex串）
     * @param privateKeyStr 私钥
     * @return
     * @throws Exception
     */
    @Override
    public String encryptByPrivateKey(String encryptStr, String privateKeyStr) throws Exception {
        return encryptByPublicKey(encryptStr, privateKeyStr);
    }

    /**
     * 由于SM2 不支持私钥加密，公钥解密，这里公钥解密实际还是调用私钥解密
     *
     * @param descyptStr   密文（hex串）
     * @param publicKeyStr 公钥
     * @return
     * @throws Exception
     */
    @Override
    public String decryptByPublicKey(String descyptStr, String publicKeyStr) throws Exception {
        return decryptByPrivateKey(descyptStr, publicKeyStr);
    }

    /**
     * SM2 私钥签名
     *
     * @param sourceStr     待签串
     * @param privateKeyStr 私钥 hex串
     * @return 签名 hex串
     * @throws Exception
     */
    @Override
    public String signByPrivateKey(String sourceStr, String privateKeyStr) throws Exception {
        return GmUtils.sm2SignStr(sourceStr, privateKeyStr);
    }

    /**
     * SM2 公钥验签
     *
     * @param signStr      签名 hex串
     * @param sourceStr    待验证 字符串
     * @param publicKeyStr 公钥 128 去除标记头后的非压缩公钥 hex串
     * @return
     * @throws Exception
     */
    @Override
    public boolean verifyByPublicKey(String signStr, String sourceStr, String publicKeyStr) throws Exception {
        return GmUtils.sm2Verify(signStr, sourceStr, publicKeyStr);
    }


    /**
     * 生成SM4 密钥
     *
     * @return
     */
    @Override
    public String genSymmetricKey() {
        return GmUtils.genSm4Key();
    }

    /**
     * 生成SM2 密钥对
     *
     * @return
     */
    @Override
    public AsymmetricKey genAsymmetricKey() {
        return GmUtils.genSm2Key();
    }


    @Override
    public boolean verifySign(BasicDto organBaseDto) {
        boolean signResult = false;
        try {
            TreeMap<String, String> verifyData = new TreeMap<>();
            String sign = organBaseDto.getSign();
            verifyData.put("lang", organBaseDto.getLang());
            verifyData.put("timestamp", organBaseDto.getTimestamp());
            if (StringUtils.isNotBlank(organBaseDto.getData())) {
                verifyData.put("data", organBaseDto.getData());
            }
            String sortedStr = BasicUtils.sort(verifyData);
            signResult = verifySignWithMessageDigest(sign, sortedStr);
        } catch (Exception e) {
            log.error("验签异常", e);
        }
        return signResult;
    }

    @Override
    public String getMctPrivateKey(String privateKey, String publicKey) {
        return GmUtils.rsaPrivateKeyToSm2PrivateKey(privateKey);
    }

    @Override
    public String getMctPublicKey(String privateKey, String publicKey) {
        return GmUtils.getSm2PublicKeyFromPrivateKey(GmUtils.rsaPrivateKeyToSm2PrivateKey(privateKey));
    }

    /**
     * 商户云 token方式访问 签名算法 ，其实就是 私钥加密
     *
     * @param sourceStr 待签字符串
     * @param privateKey 私钥
     * @return
     */
    @Override
    public String mctSignByToken(String sourceStr, String privateKey) throws Exception {
        return GmUtils.sm2SignStr(sourceStr, privateKey);
    }

    private boolean verifySignWithMessageDigest(String sign, String sortedStr) {
        String shal1 = BasicUtils.SHAL1(sortedStr);
        String signStr = messageDigest(shal1);
        return sign.equals(signStr);
    }

    @Override
    public String getDefaultKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = manageConfig.getDefaultSm4Key();
                break;
            case ORGAN:
                key = organConfig.getDefaultSm4Key();
                break;
            case MCT:
                key = mctConfig.getDefaultSm4Key();
                break;
        }
        return key;
    }

    @Override
    public String getDefaultIV(CryptoKeyConfigTypeEnum configType) {
        return null;
    }

    /**
     * 获取系统配置的密钥
     * 注意：由于SM2算法，不支持私钥加密公钥解密，所以在SM2算法下，商户云会有两对密钥。
     * 而 RSA支持，私钥加密公钥解密，所以仅需要配置一个私钥，
     *
     * @param configType
     * @return
     */
    @Override
    public String getDefaultPublicKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = null;
                break;
            case ORGAN:
                key = null;
                break;
            case MCT:
                key = mctConfig.getDefaultSm2PublicKey();
                break;
            case COUPON_APP:
                key = null;
                break;
        }
        return key;
    }

    @Override
    public String getDefaultPrivateKey(CryptoKeyConfigTypeEnum configType) {
        String key = null;
        switch (configType) {
            case ADMIN:
                key = null;
                break;
            case ORGAN:
                key = null;
                break;
            case MCT:
                key = mctConfig.getDefaultSm2PrivateKey();
                break;
            case COUPON_APP:
                key = null;
                break;
        }
        return key;
    }


}
